package cn.wh.ymcc.service.impl;


import cn.wh.ymcc.constants.BaseConstant;
import cn.wh.ymcc.constants.CommonConstants;
import cn.wh.ymcc.constants.SmsCodeConstants;
import cn.wh.ymcc.constants.YmccError;
import cn.wh.ymcc.domain.MessageSms;
import cn.wh.ymcc.dto.RedisRegisterDto;
import cn.wh.ymcc.dto.RegisterDto;
import cn.wh.ymcc.exception.GlobleException;
import cn.wh.ymcc.mapper.MessageSmsMapper;
import cn.wh.ymcc.service.IMessageSmsService;
import cn.wh.ymcc.service.IVerifyCodeSerivce;
import cn.wh.ymcc.util.AssertUtil;
import cn.wh.ymcc.util.StrUtils;
import cn.wh.ymcc.util.VerifyCodeUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 注册发送验证码
 */
@Service
@Slf4j
public class VerifyCodeSerivceImpl extends ServiceImpl<MessageSmsMapper, MessageSms> implements IVerifyCodeSerivce {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private SmsCodeConstants smsCodeConstants;

    @Autowired
    private IMessageSmsService iMessageSmsService;



    /**
     * 发送图形验证码
     * @param imageCodeKey
     * @return
     */
    @Override
    public String imageCode(String imageCodeKey) {
        //
        if (!StringUtils.hasLength(imageCodeKey)){
            throw new GlobleException("重试");
        }
        String code = StrUtils.getComplexRandomString(4);
        redisTemplate.opsForValue().set(
                imageCodeKey,
                code,
                5,
                TimeUnit.MINUTES
        );
        return VerifyCodeUtils.verifyCode(130,35,code);
    }

    /**
     * 判断进入的是账号密码登录流程还是微信绑定流程
     * @param dto
     */
    @Override
    public void smsCode(RegisterDto dto) {
            registerSmsCode(dto);
    }



    /**
     * 微信绑定需要手机验证码
     * @param dto
     */
    private void binderSmsCode(RegisterDto dto) {
        String businessKey = BaseConstant.RegisterConstants.BINDER_SMS_PREFIX + dto.getMobile();
        //发送验证码逻辑
        sendSmsCode(businessKey,dto.getMobile());
    }


    /**
     * 账号密码登录需要的的业务---图形验证码+手机验证码
     * @param dto
     */
    public void registerSmsCode(RegisterDto dto) {
        String mobile = dto.getMobile();
        String imageCode = dto.getImageCode();
        String imageCodeKey = dto.getImageCodeKey();
//          1.空校验
        AssertUtil.isNotEmpty(mobile, YmccError.COMMON_PHONE_NO_EMPTY.getMessage());
        AssertUtil.isNotEmpty(imageCode, YmccError.COMMON_IMAGECODE_NO_EMPTY.getMessage());

        AssertUtil.isPhone(mobile,YmccError.COMMON_PHONE_ILLEGAL.getMessage());//手机号不合法
//          2.校验图形验证码，根据imageCodeKey从redis获取图形验证码
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
//          。获取不到 图形验证码过期，重新获取
        if (imageCodeTmp == null){
            throw new GlobleException("图形验证码过期,请重新输入");
        }
//           。获取到了，比对图形验证码是否正确
        if (!imageCodeTmp.toString().equalsIgnoreCase(imageCode)){
//           - 不正确，提示输入图形验证码错误
            throw new GlobleException("图形验证码错误,请重新输入");
        }
//
        //根据手机号拼接key，register:17713803440，从redis获取曾今可能发送的短信验证码
        String key = String.format(CommonConstants.REGISTER_PHONE_PRIFIX, mobile);//register:17713803440
        //发送验证码逻辑
        sendSmsCode(key,mobile);
    }

    /**
     * 发送手机验证码业务 公共代码
     * @param businessKey  根据手机号拼接key，159:register，从redis获取曾今可能发送的短信验证码
     */
    private void sendSmsCode(String businessKey,String mobile) {
        Date now = new Date();
        Wrapper<MessageSms> tWrapper = new EntityWrapper<>();
        tWrapper.eq("phone",mobile);  // where phone = 123123
        List<MessageSms> sms = selectList(tWrapper);
        AssertUtil.isNotNull(sms,"没查到电话号码哦");
        for (MessageSms messageSms : sms) {
            AssertUtil.isTrue(messageSms.getState()!=-1,"用户已经被拉黑");
        }
        //        。没有注册过，往下走
//        二：短信验证码逻辑
//        1.根据手机号拼接key，159:register，从redis获取曾今可能发送的短信验证码
        String key = businessKey;
        Object smsCodeTmp = redisTemplate.opsForValue().get(key);//9527:232468742341657213
//        1.1 获取到了
        String smsCode = null;
        if(smsCodeTmp != null){
//        1.1.1 校验是否过了一分钟重发时间 value
            RedisRegisterDto redisRegisterDto = (RedisRegisterDto) smsCodeTmp;
            boolean canSend = (now.getTime() - redisRegisterDto.getTime()) / 1000 > smsCodeConstants.getInterval();
            AssertUtil.isTrue(canSend,YmccError.COMMON_SERIOUS.getMessage());
//            if(System.currentTimeMillis() - oldTime <= 1*60*1000){
////        。小于一分钟  哥屋恩
//                throw new GlobleException("使劲骂！！！");
//            }
//        。大于一分中 （还没有到3分钟，验证码还有效），
//        使用还没过期的验证码，刷新过期时间
            smsCode = redisRegisterDto.getCode();
        }else{
//        1.2 获取不到
//        1.2.1.生成新的短信验证码
            smsCode = StrUtils.getRandomString(6);
            
        }
        //储存验证码
        RedisRegisterDto smsCodeValue = new RedisRegisterDto(smsCode, now.getTime());
        //String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(
                key,
                smsCodeValue,
                smsCodeConstants.getTimeout(),
                TimeUnit.SECONDS
        );
//        4.发送短信
        //SmsUtils.sendSms(phone,"亲，您的验证码是："+smsCode+"。请在3分钟内使用！！");
        String message = String.format(smsCodeConstants.getSmsmessage(), smsCode);
        System.out.println("亲，您的验证码是：" + smsCode + "。请在3分钟内使用！！");
        log.info(message);
        saveMessageSms(now,smsCode, mobile);
    }


    private void saveMessageSms(Date now,String smsCode, String mobile) {
        MessageSms messageSms = new MessageSms();
        messageSms.setContent(smsCode);
        messageSms.setSendTime(now);
        messageSms.setPhone(mobile);
        messageSms.setTitle(smsCodeConstants.getTitle());
        // 获取请求体 request
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        messageSms.setIp(request.getRemoteAddr());//获取IP地址
        iMessageSmsService.insert(messageSms);
    }

}

